package cn.iocoder.yudao.module.system.service.auth;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO;
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserRespVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.wxlogin.config.WxSession;
import cn.iocoder.yudao.module.system.controller.admin.kuaishou.config.KuaishouSession;
import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.UserAssetsDO;
import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper;
import cn.iocoder.yudao.module.system.dal.mysql.user.UserAssetsMapper;
import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2ClientConstants;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.module.system.service.logger.LoginLogService;
import cn.iocoder.yudao.module.system.service.member.MemberService;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
import cn.iocoder.yudao.module.system.service.social.SocialUserService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import cn.iocoder.yudao.module.system.service.useractivity.UserActivityRecordService;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.annotations.VisibleForTesting;
import com.google.gson.Gson;
import com.xingyuv.captcha.model.common.ResponseModel;
import com.xingyuv.captcha.model.vo.CaptchaVO;
import com.xingyuv.captcha.service.CaptchaService;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.validation.Validator;
import java.io.IOException;
import java.util.List;
import java.util.Objects;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;

/**
 * Auth Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Slf4j
public class AdminAuthServiceImpl implements AdminAuthService {
    private static String appId = "wx3537f1c705d5090f";//AppID(小程序ID)
    private static String secret = "64705c89596b01d1a0063baca5aa381d";//AppSecret(小程序密钥)

    private static String appId2 = "wx5ca052de959465df";
    private static String secret2 = "21680badc8435f3ed5231771005f6d15";

    // 快手相关配置 - 从配置文件读取
    @Value("${kuaishou.app-id:your_kuaishou_app_id}")
    private String kuaishouAppId;

    @Value("${kuaishou.secret:your_kuaishou_secret}")
    private String kuaishouSecret;
    @Resource
    private AdminUserService userService;
    @Resource
    private LoginLogService loginLogService;
    @Resource
    private OAuth2TokenService oauth2TokenService;
    @Resource
    private SocialUserService socialUserService;
    @Resource
    private MemberService memberService;
    @Resource
    private Validator validator;
    @Resource
    private CaptchaService captchaService;
    @Resource
    private SmsCodeApi smsCodeApi;

    @Autowired
    private AdminUserMapper userMapper;

    @Autowired
    private UserAssetsMapper userAssetsMapper;

    @Resource
    private UserActivityRecordService userActivityRecordService;

    /**
     * 验证码的开关，默认为 true
     */
    @Value("${yudao.captcha.enable:true}")
    @Setter // 为了单测：开启或者关闭验证码
    private Boolean captchaEnable;

    @Override
    public AdminUserDO authenticate(String username, String password) {
        final LoginLogTypeEnum logTypeEnum = LoginLogTypeEnum.LOGIN_USERNAME;
        // 校验账号是否存在
        AdminUserDO user = userService.getUserByUsername(username);
        if (user == null) {
            createLoginLog(null, username, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS);
            throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
        }
        if (!userService.isPasswordMatch(password, user.getPassword())) {
            createLoginLog(user.getId(), username, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS);
            throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
        }
        // 校验是否禁用
        if (CommonStatusEnum.isDisable(user.getStatus())) {
            createLoginLog(user.getId(), username, logTypeEnum, LoginResultEnum.USER_DISABLED);
            throw exception(AUTH_LOGIN_USER_DISABLED);
        }
        return user;
    }

    @Override
    public AuthLoginRespVO login(AuthLoginReqVO reqVO) {
        // 校验验证码
        validateCaptcha(reqVO);

        // 使用账号密码，进行登录
        AdminUserDO user = authenticate(reqVO.getUsername(), reqVO.getPassword());

        // 如果 socialType 非空，说明需要绑定社交用户
        if (reqVO.getSocialType() != null) {
            socialUserService.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(),
                    reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState()));
        }

        // 如果提供了平台和code，重新获取并更新对应平台的openid
        if (reqVO.getPlatform() != null && reqVO.getCode() != null) {
            updateUserOpenIdByPlatform(user, reqVO.getPlatform(), reqVO.getCode());
            // 重新获取更新后的用户信息
            user = userService.getUser(user.getId());
        }

        // 创建 Token 令牌，记录登录日志
        AuthLoginRespVO authLoginRespVO = createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME);

        // 设置用户信息到返回对象中
        UserRespVO userRespVO = new UserRespVO();
        BeanUtils.copyProperties(user, userRespVO);
        authLoginRespVO.setUserRespVO(userRespVO);

        // 设置各平台openId到返回对象中
        if (StrUtil.isNotEmpty(user.getWechatOpenId())) {
            authLoginRespVO.setWechatOpenId(user.getWechatOpenId());
        }
        if (StrUtil.isNotEmpty(user.getKuaishouOpenId())) {
            authLoginRespVO.setKuaishouOpenId(user.getKuaishouOpenId());
        }
        // 保留兼容性
        if (StrUtil.isNotEmpty(user.getOpenId())) {
            authLoginRespVO.setOpenId(user.getOpenId());
        }

        // 设置手机号绑定状态
        authLoginRespVO.setMobileBound(StrUtil.isNotBlank(user.getMobile()));

        return authLoginRespVO;
    }

    @Override
    public void sendSmsCode(AuthSmsSendReqVO reqVO) {
        // 如果是重置密码场景，需要校验图形验证码是否正确
        if (Objects.equals(SmsSceneEnum.ADMIN_MEMBER_RESET_PASSWORD.getScene(), reqVO.getScene())) {
            ResponseModel response = doValidateCaptcha(reqVO);
            if (!response.isSuccess()) {
                throw exception(AUTH_REGISTER_CAPTCHA_CODE_ERROR, response.getRepMsg());
            }
        }

        // 登录场景，验证是否存在
//        if (userService.getUserByMobile(reqVO.getMobile()) == null) {
//            throw exception(AUTH_MOBILE_NOT_EXISTS);
//        }
        // 发送验证码
        smsCodeApi.sendSmsCode(AuthConvert.INSTANCE.convert(reqVO).setCreateIp(getClientIP()));
    }

    @Override
    public AuthLoginRespVO smsLogin(AuthSmsLoginReqVO reqVO) {
        // 校验验证码
        smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.ADMIN_MEMBER_LOGIN.getScene(), getClientIP()));

        // 获得用户信息
        AdminUserDO user = userService.getUserByMobile(reqVO.getMobile());
        if (user == null) {
            // 用户不存在，自动创建用户
            user = createUserForSmsLogin(reqVO.getMobile());
        }

        // 创建 Token 令牌，记录登录日志
        AuthLoginRespVO authLoginRespVO = createTokenAfterLoginSuccess(user.getId(), reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE);
        
        // 设置手机号绑定状态
        authLoginRespVO.setMobileBound(StrUtil.isNotBlank(user.getMobile()));
        
        return authLoginRespVO;
    }

    /**
     * 为短信登录创建用户
     *
     * @param mobile 手机号
     * @return 创建的用户
     */
    private AdminUserDO createUserForSmsLogin(String mobile) {
        // 构建用户创建请求
        UserSaveReqVO createReqVO = new UserSaveReqVO();
        createReqVO.setUsername(mobile); // 使用手机号作为用户名
        createReqVO.setNickname("用户" + mobile.substring(mobile.length() - 4)); // 使用手机号后4位作为昵称
        createReqVO.setMobile(mobile);
        createReqVO.setPassword("123456"); // 设置默认密码
        createReqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认启用状态
        
        // 创建用户
        Long userId = userService.createUser(createReqVO);
        
        // 返回创建的用户
        return userService.getUser(userId);
    }

    private void createLoginLog(Long userId, String username,
                                LoginLogTypeEnum logTypeEnum, LoginResultEnum loginResult) {
        // 插入登录日志
        LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO();
        reqDTO.setLogType(logTypeEnum.getType());
        reqDTO.setTraceId(TracerUtils.getTraceId());
        reqDTO.setUserId(userId);
        reqDTO.setUserType(getUserType().getValue());
        reqDTO.setUsername(username);
        reqDTO.setUserAgent(ServletUtils.getUserAgent());
        reqDTO.setUserIp(ServletUtils.getClientIP());
        reqDTO.setResult(loginResult.getResult());
        loginLogService.createLoginLog(reqDTO);
        // 更新最后登录时间
        if (userId != null && Objects.equals(LoginResultEnum.SUCCESS.getResult(), loginResult.getResult())) {
            userService.updateUserLogin(userId, ServletUtils.getClientIP());
        }
    }

    @Override
    public AuthLoginRespVO socialLogin(AuthSocialLoginReqVO reqVO) {
        // 使用 code 授权码，进行登录。然后，获得到绑定的用户编号
        SocialUserRespDTO socialUser = socialUserService.getSocialUserByCode(UserTypeEnum.ADMIN.getValue(), reqVO.getType(),
                reqVO.getCode(), reqVO.getState());
        if (socialUser == null || socialUser.getUserId() == null) {
            throw exception(AUTH_THIRD_LOGIN_NOT_BIND);
        }

        // 获得用户
        AdminUserDO user = userService.getUser(socialUser.getUserId());
        if (user == null) {
            throw exception(USER_NOT_EXISTS);
        }

        // 创建 Token 令牌，记录登录日志
        return createTokenAfterLoginSuccess(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL);
    }

    @VisibleForTesting
    void validateCaptcha(AuthLoginReqVO reqVO) {
        ResponseModel response = doValidateCaptcha(reqVO);
        // 校验验证码
        if (!response.isSuccess()) {
            // 创建登录失败日志（验证码不正确)
            createLoginLog(null, reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME, LoginResultEnum.CAPTCHA_CODE_ERROR);
            throw exception(AUTH_LOGIN_CAPTCHA_CODE_ERROR, response.getRepMsg());
        }
    }

    private ResponseModel doValidateCaptcha(CaptchaVerificationReqVO reqVO) {
        // 如果验证码关闭，则不进行校验
        if (!captchaEnable) {
            return ResponseModel.success();
        }
        ValidationUtils.validate(validator, reqVO, CaptchaVerificationReqVO.CodeEnableGroup.class);
        CaptchaVO captchaVO = new CaptchaVO();
        captchaVO.setCaptchaVerification(reqVO.getCaptchaVerification());
        return captchaService.verification(captchaVO);
    }

    /**
     * 用户小程序登录登录
     *
     * @param code 前端传来的码
     */
    @Override
    public AuthLoginRespVO wechatLogin(String code) {
        log.info("开始微信登录，接收到的授权码: {}", code);
        
        WxSession session = null;
        String usedAppId = null;
        
        // 首先尝试使用第一个appId和secret
        try {
            log.info("尝试使用第一个AppID进行微信登录: {}", appId);
            session = getSessionKeyFromWxByCodeWithAppInfo(code, appId, secret);
            usedAppId = appId;
            log.info("第一个AppID登录成功，AppID: {}", appId);
        } catch (Exception e) {
            log.warn("第一个AppID登录失败，AppID: {}, 错误信息: {}", appId, e.getMessage());
            
            // 第一个登录失败，尝试使用第二个appId和secret
            try {
                log.info("尝试使用第二个AppID进行微信登录: {}", appId2);
                session = getSessionKeyFromWxByCodeWithAppInfo(code, appId2, secret2);
                usedAppId = appId2;
                log.info("第二个AppID登录成功，AppID: {}", appId2);
            } catch (Exception e2) {
                log.error("第二个AppID登录也失败，AppID: {}, 错误信息: {}", appId2, e2.getMessage());
                // 两个都失败了，记录详细错误并抛出异常
                String errorMsg = String.format("所有微信AppID登录均失败。第一个AppID(%s)错误: %s; 第二个AppID(%s)错误: %s", 
                                               appId, e.getMessage(), appId2, e2.getMessage());
                log.error("微信登录完全失败: {}", errorMsg);
                throw new RuntimeException(errorMsg);
            }
        }
        
        log.info("微信登录成功，获得openId: {}, 使用AppID: {}", session.getOpenId(), usedAppId);
        log.debug("微信登录session详情: {}", session);
        
        //查询是否存在这个用户
        if (session.getOpenId() == null) {
            log.error("微信登录失败：未获取到有效的openId");
            throw new RuntimeException("微信登录失败：未获取到有效的openId");
        }
        
        AdminUserDO user = null;

        // 优先使用微信专用字段查询，兼容旧数据
        List<AdminUserDO> users = userMapper.selectList(new QueryWrapper<AdminUserDO>().eq("wechat_open_id", session.getOpenId()));
        if (users != null&& !users.isEmpty()) {
            user = users.get(0);
        }
        if (user == null) {
            user = userService.getUserByOpenId(session.getOpenId());
        }

        //如果用户不存在 就创建用户
        if (user == null) {
            user = new AdminUserDO();
            user.setUsername(RandomUtil.randomNumbers(8));
            user.setPassword(RandomUtil.randomString(10));
            user.setNickname("用户" + RandomUtil.randomNumbers(8));
            user.setStatus(0);
            user.setWechatOpenId(session.getOpenId()); // 使用微信专用字段
            user.setOpenId(session.getOpenId()); // 保留兼容性
            userMapper.insert(user);
            user = userService.getUserByWechatOpenId(session.getOpenId());

            UserAssetsDO userAssetsDO = new UserAssetsDO();
            userAssetsDO.setUserId(user.getId());
            userAssetsMapper.insert(userAssetsDO);
            user = userService.getUserByWechatOpenId(session.getOpenId());
        }

        //生成token,存储进入redis，返回给前端
        AuthLoginRespVO authLoginRespVO = createTokenAfterLoginSuccess(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME);
        //将token返回给前端
        UserRespVO u = new UserRespVO();
        BeanUtils.copyProperties(user, u);

        authLoginRespVO.setUserRespVO(u);

        return authLoginRespVO;
    }


    public static WxSession getSessionKeyFromWxByCode(String code) {
        return getSessionKeyFromWxByCodeWithAppInfo(code, appId, secret);
    }

    /**
     * 使用指定的appId和secret获取微信session
     * @param code 微信授权码
     * @param appId 小程序AppID
     * @param secret 小程序密钥
     * @return WxSession对象
     */
    public static WxSession getSessionKeyFromWxByCodeWithAppInfo(String code, String appId, String secret) {
        String url = "https://api.weixin.qq.com/sns/jscode2session"
                + "?appid=" + appId
                + "&secret=" + secret
                + "&js_code=" + code
                + "&grant_type=authorization_code";
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(url);
        try {
            String response = httpClient.execute(httpGet, httpResponse -> {
                int statusCode = httpResponse.getStatusLine().getStatusCode();
                if (statusCode == 200) {
                    return EntityUtils.toString(httpResponse.getEntity());
                }
                throw new RuntimeException("微信接口调用失败，状态码：" + statusCode);
            });
            log.debug("微信登录API响应 (AppID: {}): {}", appId, response);
            
            // 解析微信接口返回的数据
            JSONObject jsonObject = JSONObject.parseObject(response);
            
            // 检查是否有错误码
            Integer errcode = jsonObject.getInteger("errcode");
            if (errcode != null && errcode != 0) {
                String errmsg = jsonObject.getString("errmsg");
                throw new RuntimeException("微信登录失败，错误码：" + errcode + "，错误信息：" + errmsg);
            }
            
            String openid = jsonObject.getString("openid");
            String sessionKey = jsonObject.getString("session_key");
            String unionid = jsonObject.getString("unionid");

            // 创建 WxSession 对象
            WxSession wxSession = new WxSession();
            wxSession.setOpenId(openid);
            wxSession.setSession_key(sessionKey);
            wxSession.setUnionid(unionid);

            return wxSession;
        } catch (IOException e) {
            throw new RuntimeException("网络请求失败：" + e.getMessage(), e);
        } finally {
            try {
                httpClient.close();
            } catch (IOException e) {
                throw new RuntimeException("关闭HTTP客户端失败：" + e.getMessage(), e);
            }
        }
    }

    private AuthLoginRespVO createTokenAfterLoginSuccess(Long userId, String username, LoginLogTypeEnum logType) {
        // 插入登陆日志
        createLoginLog(userId, username, logType, LoginResultEnum.SUCCESS);
        
        // 记录用户登录活动
        try {
            userActivityRecordService.recordLoginActivity(userId, username, getUserType().getValue(),
                    getClientIP(), ServletUtils.getUserAgent(), null);
        } catch (Exception e) {
            log.warn("记录用户登录活动失败", e);
        }
        
        // 创建访问令牌
        OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken(userId, getUserType().getValue(),
                OAuth2ClientConstants.CLIENT_ID_DEFAULT, null);
        // 构建返回结果
        return AuthConvert.INSTANCE.convert(accessTokenDO);
    }

    @Override
    public AuthLoginRespVO refreshToken(String refreshToken) {
        OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.refreshAccessToken(refreshToken, OAuth2ClientConstants.CLIENT_ID_DEFAULT);
        return AuthConvert.INSTANCE.convert(accessTokenDO);
    }

    @Override
    public void logout(String token, Integer logType) {
        // 删除访问令牌
        OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.removeAccessToken(token);
        if (accessTokenDO == null) {
            return;
        }
        // 删除成功，则记录登出日志
        createLogoutLog(accessTokenDO.getUserId(), accessTokenDO.getUserType(), logType);
    }

    private void createLogoutLog(Long userId, Integer userType, Integer logType) {
        LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO();
        reqDTO.setLogType(logType);
        reqDTO.setTraceId(TracerUtils.getTraceId());
        reqDTO.setUserId(userId);
        reqDTO.setUserType(userType);
        if (ObjectUtil.equal(getUserType().getValue(), userType)) {
            reqDTO.setUsername(getUsername(userId));
        } else {
            reqDTO.setUsername(memberService.getMemberUserMobile(userId));
        }
        reqDTO.setUserAgent(ServletUtils.getUserAgent());
        reqDTO.setUserIp(ServletUtils.getClientIP());
        reqDTO.setResult(LoginResultEnum.SUCCESS.getResult());
        loginLogService.createLoginLog(reqDTO);
    }

    private String getUsername(Long userId) {
        if (userId == null) {
            return null;
        }
        AdminUserDO user = userService.getUser(userId);
        return user != null ? user.getUsername() : null;
    }

    private UserTypeEnum getUserType() {
        return UserTypeEnum.ADMIN;
    }

    @Override
    public AuthLoginRespVO register(AuthRegisterReqVO registerReqVO) {
        // 1. 校验验证码
        validateCaptcha(registerReqVO);

        // 2. 如果提供了平台和code，获取openid
        String openId = null;
        if (registerReqVO.getPlatform() != null && registerReqVO.getCode() != null) {
            openId = getOpenIdByPlatformAndCode(registerReqVO.getPlatform(), registerReqVO.getCode());
        }

        // 3. 校验用户名是否已存在，并创建用户
        Long userId = userService.registerUser(registerReqVO, openId, registerReqVO.getPlatform());

        // 4. 创建 Token 令牌，记录登录日志
        AuthLoginRespVO authLoginRespVO = createTokenAfterLoginSuccess(userId, registerReqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME);

        // 5. 获取完整的用户信息并设置到返回对象中
        AdminUserDO user = userService.getUser(userId);
        if (user != null) {
            UserRespVO userRespVO = new UserRespVO();
            BeanUtils.copyProperties(user, userRespVO);
            authLoginRespVO.setUserRespVO(userRespVO);

            // 设置各平台openId到返回对象中
            if (StrUtil.isNotEmpty(user.getWechatOpenId())) {
                authLoginRespVO.setWechatOpenId(user.getWechatOpenId());
            }
            if (StrUtil.isNotEmpty(user.getKuaishouOpenId())) {
                authLoginRespVO.setKuaishouOpenId(user.getKuaishouOpenId());
            }
            // 保留兼容性
            if (StrUtil.isNotEmpty(user.getOpenId())) {
                authLoginRespVO.setOpenId(user.getOpenId());
            }
        }

        return authLoginRespVO;
    }

    /**
     * 根据平台类型和授权码获取openid
     */
    private String getOpenIdByPlatformAndCode(Integer platform, String code) {
        if (Integer.valueOf(34).equals(platform)) {
            // 微信小程序 (WECHAT_MINI_APP = 34)
            WxSession session = getSessionKeyFromWxByCode(code);
            return session.getOpenId();
        } else if (Integer.valueOf(40).equals(platform)) {
            // 快手 (KUAISHOU = 40)
            KuaishouSession session = getKuaishouSessionByCode(code);
            return session.getOpenId();
        } else {
            throw exception(AUTH_LOGIN_FAIL, "不支持的平台类型: " + platform);
        }
    }

    /**
     * 根据平台类型更新用户的openid
     */
    private void updateUserOpenIdByPlatform(AdminUserDO user, Integer platform, String code) {
        try {
            String openId = getOpenIdByPlatformAndCode(platform, code);
            if (StrUtil.isEmpty(openId)) {
                log.warn("获取到的openId为空，平台: {}, 用户ID: {}", platform, user.getId());
                return;
            }

            // 根据平台类型更新相应的openId字段
            if (Integer.valueOf(34).equals(platform)) {
                // 微信小程序
                user.setWechatOpenId(openId);
                user.setOpenId(openId); // 保留兼容性
                log.info("更新用户微信openId，用户ID: {}, openId: {}", user.getId(), openId);
            } else if (Integer.valueOf(40).equals(platform)) {
                // 快手
                user.setKuaishouOpenId(openId);
                user.setOpenId(openId); // 保留兼容性
                log.info("更新用户快手openId，用户ID: {}, openId: {}", user.getId(), openId);
            }

            // 更新数据库
            userMapper.updateById(user);

        } catch (Exception e) {
            log.error("更新用户openId失败，平台: {}, 用户ID: {}, 错误: {}", platform, user.getId(), e.getMessage(), e);
            // 不抛出异常，避免影响正常登录流程
        }
    }

    @VisibleForTesting
    void validateCaptcha(AuthRegisterReqVO reqVO) {
        ResponseModel response = doValidateCaptcha(reqVO);
        // 验证不通过
        if (!response.isSuccess()) {
            throw exception(AUTH_REGISTER_CAPTCHA_CODE_ERROR, response.getRepMsg());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resetPassword(AuthResetPasswordReqVO reqVO) {
        AdminUserDO userByMobile = userService.getUserByMobile(reqVO.getMobile());
        if (userByMobile == null) {
            throw exception(USER_MOBILE_NOT_EXISTS);
        }

        smsCodeApi.useSmsCode(new SmsCodeUseReqDTO()
                .setCode(reqVO.getCode())
                .setMobile(reqVO.getMobile())
                .setScene(SmsSceneEnum.ADMIN_MEMBER_RESET_PASSWORD.getScene())
                .setUsedIp(getClientIP())
        );

        userService.updateUserPassword(userByMobile.getId(), reqVO.getPassword());
    }

    @Override
    public AuthLoginRespVO kuaishouLogin(KuaishouLoginParam param) {
        System.out.println("接收到快手登录参数: " + param);

        String openId;
        // 如果直接传了openid，则使用openid；否则通过code获取openid
        if (param.getOpenid() != null && !param.getOpenid().isEmpty()) {
            openId = param.getOpenid();
            System.out.println("直接使用传入的快手openId: " + openId);
        } else if (param.getCode() != null && !param.getCode().isEmpty()) {
            // 通过code获取快手用户信息
            KuaishouSession session = getKuaishouSessionByCode(param.getCode());
            openId = session.getOpenId();
            System.out.println("通过code获取的快手openId: " + openId);
        } else {
            throw exception(AUTH_LOGIN_FAIL);
        }

        if (openId == null || openId.isEmpty()) {
            throw exception(AUTH_LOGIN_FAIL);
        }

        // 优先使用快手专用字段查询，兼容旧数据
        AdminUserDO user = userService.getUserByKuaishouOpenId(openId);
        if (user == null) {
            user = userService.getUserByOpenId(openId);
        }

        // 如果用户不存在就创建用户
        if (user == null) {
            user = new AdminUserDO();
            user.setUsername(RandomUtil.randomNumbers(8)); // 统一使用8位数字
            user.setPassword(RandomUtil.randomString(10));
            user.setNickname("用户" + RandomUtil.randomNumbers(8));
            user.setStatus(0);
            user.setKuaishouOpenId(openId); // 使用快手专用字段
            user.setOpenId(openId); // 保留兼容性
            userMapper.insert(user);
            user = userService.getUserByKuaishouOpenId(openId);

            // 创建用户资产记录
            UserAssetsDO userAssetsDO = new UserAssetsDO();
            userAssetsDO.setUserId(user.getId());
            userAssetsMapper.insert(userAssetsDO);
            user = userService.getUserByKuaishouOpenId(openId);
        }

        // 生成token，存储进入redis，返回给前端
        AuthLoginRespVO authLoginRespVO = createTokenAfterLoginSuccess(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME);

        // 将用户信息返回给前端
        UserRespVO u = new UserRespVO();
        BeanUtils.copyProperties(user, u);
        authLoginRespVO.setUserRespVO(u);

        return authLoginRespVO;
    }

    /**
     * 通过快手code获取用户信息
     * 调用快手真实API获取用户openid和基本信息
     */
    private KuaishouSession getKuaishouSessionByCode(String code) {
        String url = "https://open.kuaishou.com/oauth2/mp/code2session";

        CloseableHttpClient httpClient = HttpClients.createDefault();
        try {
            // 构建请求参数
            String requestBody = "app_id=" + kuaishouAppId
                    + "&app_secret=" + kuaishouSecret
                    + "&js_code=" + code
                   ;

            HttpPost httpPost = new HttpPost(url);
            httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
            httpPost.setEntity(new StringEntity(requestBody, "UTF-8"));

            String response = httpClient.execute(httpPost, httpResponse -> {
                int statusCode = httpResponse.getStatusLine().getStatusCode();
                if (statusCode == 200) {
                    return EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
                }
                throw new RuntimeException("快手接口调用失败，状态码：" + statusCode);
            });

            System.out.println("快手登录响应: " + response);

            // 解析快手接口返回的数据
            JSONObject jsonObject = JSONObject.parseObject(response);

            // 检查是否有错误
            if (jsonObject.containsKey("error_code")) {
                String errorMsg = jsonObject.getString("error_msg");
                throw new RuntimeException("快手API返回错误: " + errorMsg);
            }

            String accessToken = jsonObject.getString("access_token");
            String openId = jsonObject.getString("open_id");
            String refreshToken = jsonObject.getString("refresh_token");

            // 创建快手会话对象，暂时不获取详细用户信息
            KuaishouSession session = new KuaishouSession();
            session.setOpenId(openId);
            session.setAccessToken(accessToken);
            session.setRefreshToken(refreshToken);
            session.setNickname("快手用户"); // 默认昵称
            session.setAvatar(""); // 默认头像为空

            return session;

        } catch (IOException e) {
            throw new RuntimeException("调用快手API失败", e);
        } finally {
            try {
                httpClient.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }


}
